Advertisement
ElegantAlchemist

Voltmeter 2019

Jan 27th, 2019
4,753
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.94 KB | None | 0 0
  1. /**
  2. * Voltmeter Clock - 2019
  3. * A clock using converted analogue 1000v meters and PWM to tell the time
  4. * Inspired by u/MrMaverick82 (Michael Teeuw) reddit post: https://www.reddit.com/r/DIY/comments/8s1efr/due_to_my_dads_fascination_for_analog_volt_meters/
  5. * Most of the code here is from above project, with some additions/subtractions
  6. * Original code and project can be found: https://github.com/MichMich/AnalogVoltMeterClock
  7. * This project code can be found: https://pastebin.com/gdq0zPUh
  8. *
  9. * ADDED: Automatic adjustment for Daylight Savings
  10. * ADDED: Colour adjustable RGB LEDs for effects (simple here, could be as complex as desired,
  11. * different colours for AM/PM etc etc)
  12. *
  13. * LICENSE: Permission is hereby granted, free of charge, to any person
  14. * obtaining a copy of this software and associated documentation files
  15. * (the "Software"). For more info see LICENSE at bottom of this file.
  16. */
  17.  
  18. #include <DS3232RTC.h> // https://github.com/PaulStoffregen/DS1307RTC
  19. #include <Timezone.h> // https://github.com/JChristensen/Timezone
  20. #include <TimeLib.h>
  21. #include "RTClib.h"
  22. #include <Arduino.h>
  23. #include <Wire.h>
  24. #include <Adafruit_NeoPixel.h>
  25. #include <Streaming.h>
  26.  
  27. // Define the Pins we are using.
  28. #define PIN_METER_HOUR 3
  29. #define PIN_METER_MIN 5
  30. #define PIN_METER_SEC 6
  31.  
  32. // Define the minimum and maximum PWM values for all the meters.
  33. // These values can be used to calibrate the meters.
  34. #define MINIMUM_PWM_VALUE_HOUR 18
  35. #define MAXIMUM_PWM_VALUE_HOUR 240
  36. #define MINIMUM_PWM_VALUE_MIN 1
  37. #define MAXIMUM_PWM_VALUE_MIN 221
  38. #define MINIMUM_PWM_VALUE_SEC 5
  39. #define MAXIMUM_PWM_VALUE_SEC 235
  40.  
  41. //Define the neopixel settings
  42. #define PIN 2
  43. #define NUMPIXELS 3
  44.  
  45. Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
  46.  
  47. TimeChangeRule BST = {"BST", Last, Sun, Mar, 1, 60}; //British Summer Time
  48. TimeChangeRule GMT = {"GMT", Last, Sun, Oct, 2, 0}; //Standard Time
  49. Timezone UK(BST, GMT);
  50.  
  51. // If TimeChangeRules are already stored in EEPROM, comment out the three
  52. // lines above and uncomment the line below.
  53. //Timezone myTZ(100); //assumes rules stored at EEPROM address 100
  54.  
  55. TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev
  56. time_t utc, local;
  57.  
  58. void setup()
  59. {
  60. Serial.begin(115200);
  61. setSyncProvider(RTC.get); // the function to get the time from the RTC
  62. if(timeStatus()!= timeSet)
  63. Serial.println("Unable to sync with the RTC");
  64. else
  65. Serial.println("RTC has set the system time");
  66.  
  67. // Configure all the pin modes for all connected pins.
  68. pinMode(PIN_METER_HOUR, OUTPUT);
  69. pinMode(PIN_METER_MIN, OUTPUT);
  70. pinMode(PIN_METER_SEC, OUTPUT);
  71.  
  72. //start the neopixel library
  73. pixels.begin();
  74.  
  75. // Initiate the power-on self test by running the start sequence.
  76. startSequence();
  77. }
  78.  
  79. void loop(void)
  80. {
  81. Serial.println();
  82. utc = now();
  83. printTime(utc, "UTC");
  84. local = UK.toLocal(utc, &tcr);
  85. printTime(local, tcr -> abbrev);
  86. delay(1000);
  87. static time_t tLast;
  88. time_t t;
  89. tmElements_t tm;
  90.  
  91. //check for input to set the RTC, minimum length is 12, i.e. yy,m,d,h,m,s
  92. if (Serial.available() >= 12) {
  93. //note that the tmElements_t Year member is an offset from 1970,
  94. //but the RTC wants the last two digits of the calendar year.
  95. //use the convenience macros from Time.h to do the conversions.
  96. int y = Serial.parseInt();
  97. if (y >= 100 && y < 1000)
  98. Serial << F("Error: Year must be two digits or four digits!") << endl;
  99. else {
  100. if (y >= 1000)
  101. tm.Year = CalendarYrToTm(y);
  102. else //(y < 100)
  103. tm.Year = y2kYearToTm(y);
  104. tm.Month = Serial.parseInt();
  105. tm.Day = Serial.parseInt();
  106. tm.Hour = Serial.parseInt();
  107. tm.Minute = Serial.parseInt();
  108. tm.Second = Serial.parseInt();
  109. t = makeTime(tm);
  110. RTC.set(t); //use the time_t value to ensure correct weekday is set
  111. setTime(t);
  112. Serial << F("RTC set to: ");
  113. printTime(t, local);
  114. Serial << endl;
  115. //dump any extraneous input
  116. while (Serial.available() > 0) Serial.read();
  117. }
  118. }
  119.  
  120. t = now();
  121. if (t != tLast) {
  122. tLast = t;
  123. if (second(t) == 0) {
  124. float c = RTC.temperature() / 4.;
  125. float f = c * 9. / 5. + 32.;
  126. Serial << F(" ") << c << F(" C ") << f << F(" F");
  127. }
  128.  
  129. // Update the meters by calling the `displayTime()` method.
  130. displayTime();
  131.  
  132. Serial << endl;
  133.  
  134. }
  135. }
  136.  
  137. // format and print a time_t value, with a time zone appended.
  138. void printDateTime(time_t t, const char *tz)
  139. {
  140. char buf[32];
  141. char m[4]; // temporary storage for month string (DateStrings.cpp uses shared buffer)
  142. strcpy(m, monthShortStr(month(t)));
  143. sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s",
  144. hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz);
  145. Serial.println(buf);
  146. }
  147.  
  148. /**
  149. * Slowly animate one meter to the maximum value and back.
  150. * This animation is used in the start sequence. Not only does it look
  151. * cool. It's also a way to test the meters.
  152. *
  153. * @param uint8_t pin The pin of the meter.
  154. * @param uint8_t min The meter's minimum PWM value.
  155. * @param uint8_t max The meter's maximum PWM value.
  156. */
  157. void animateMeter(uint8_t pin, uint8_t min, uint8_t max) {
  158. uint8_t v;
  159. for (v = min; v <= max; v++) {
  160. analogWrite(pin, v);
  161. delay(2);
  162. }
  163. delay(100);
  164. for (v = max; v >= min; v--) {
  165. analogWrite(pin, v);
  166. delay(2);
  167. }
  168. delay(100);
  169. }
  170.  
  171. /**
  172. * Run the startup sequence by animating all three meters sequentially.
  173. */
  174. void startSequence() {
  175. pixels.setPixelColor(0, pixels.Color(255,51,20));
  176. pixels.setPixelColor(1, pixels.Color(255,51,20));
  177. pixels.setPixelColor(2, pixels.Color(255,51,20));
  178. pixels.show();
  179. delay(500);
  180. pixels.setPixelColor(0, pixels.Color(0,0,0));
  181. pixels.setPixelColor(1, pixels.Color(0,0,0));
  182. pixels.setPixelColor(2, pixels.Color(0,0,0));
  183. pixels.show();
  184. delay(500);
  185. pixels.setPixelColor(0, pixels.Color(255,51,20));
  186. pixels.setPixelColor(1, pixels.Color(255,51,20));
  187. pixels.setPixelColor(2, pixels.Color(255,51,20));
  188. pixels.show();
  189. delay(500);
  190. pixels.setPixelColor(0, pixels.Color(0,0,0));
  191. pixels.setPixelColor(1, pixels.Color(0,0,0));
  192. pixels.setPixelColor(2, pixels.Color(0,0,0));
  193. pixels.show();
  194. delay(500);
  195. pixels.setPixelColor(0, pixels.Color(255,51,20));
  196. pixels.setPixelColor(1, pixels.Color(255,51,20));
  197. pixels.setPixelColor(2, pixels.Color(255,51,20));
  198. pixels.show();
  199. delay(250);
  200. animateMeter(PIN_METER_HOUR, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR);
  201. animateMeter(PIN_METER_MIN, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN);
  202. animateMeter(PIN_METER_SEC, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC);
  203. }
  204.  
  205. /**
  206. * The method to update the time displayed on the the meter.
  207. */
  208. void displayTime() {
  209. // Since the real time clock returns a 24 hour format,
  210. // we need to convert the hour value to 12 hour format and store in temporary variable 'h'.
  211. // For minutes and seconds we can just directly use the
  212. // properties on the 'time(local)' object. No need to store those
  213. // in a temporary variable.
  214. int8_t h = (hour(local) == 0 || hour(local) == 12) ? 12 : hour(local) % 12;
  215.  
  216. // Convert the time values to PWM values by using map ...
  217. // and set that value as the PWM value using analogWrite.
  218. analogWrite(PIN_METER_HOUR, map(h, 1, 12, MINIMUM_PWM_VALUE_HOUR, MAXIMUM_PWM_VALUE_HOUR));
  219. analogWrite(PIN_METER_MIN, map(minute(local), 0, 60, MINIMUM_PWM_VALUE_MIN, MAXIMUM_PWM_VALUE_MIN));
  220. analogWrite(PIN_METER_SEC, map(second(local), 0, 60, MINIMUM_PWM_VALUE_SEC, MAXIMUM_PWM_VALUE_SEC));
  221. }
  222.  
  223. //Function to print time with time zone
  224. void printTime(time_t t, char *tz)
  225. {
  226. sPrintI00(hour(t));
  227. sPrintDigits(minute(t));
  228. sPrintDigits(second(t));
  229. Serial.print(' ');
  230. Serial.print(dayShortStr(weekday(t)));
  231. Serial.print(' ');
  232. sPrintI00(day(t));
  233. Serial.print(' ');
  234. Serial.print(monthShortStr(month(t)));
  235. Serial.print(' ');
  236. Serial.print(year(t));
  237. Serial.print(' ');
  238. Serial.print(tz);
  239. Serial.println();
  240. }
  241.  
  242. //Print an integer in "00" format (with leading zero).
  243. //Input value assumed to be between 0 and 99.
  244. void sPrintI00(int val)
  245. {
  246. if (val < 10) Serial.print('0');
  247. Serial.print(val, DEC);
  248. return;
  249. }
  250.  
  251. //Print an integer in ":00" format (with leading zero).
  252. //Input value assumed to be between 0 and 99.
  253. void sPrintDigits(int val)
  254. {
  255. Serial.print(':');
  256. if(val < 10) Serial.print('0');
  257. Serial.print(val, DEC);
  258. }
  259.  
  260. /**
  261. * ORIGINAL CODE Copyright (c) 2018 Michael Teeuw
  262. * MODIFIED CODE Copyright (c) 2019 Andrew O'Donnell
  263. *
  264. * Permission is hereby granted, free of charge, to any person obtaining a copy
  265. * of this software and associated documentation files (the "Software"), to deal
  266. * in the Software without restriction, including without limitation the rights
  267. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  268. * copies of the Software, and to permit persons to whom the Software is
  269. * furnished to do so, subject to the following conditions:
  270. *
  271. * The above copyright notice and this permission notice shall be included in all
  272. * copies or substantial portions of the Software.
  273. *
  274. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  275. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  276. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  277. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  278. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  279. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  280. * SOFTWARE.
  281. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement